{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## ColorScale\n",
    "\n",
    "The colors for the `ColorScale` can be defined one of two ways:\n",
    "- Manually, by setting the scale's `colors` attribute to a list of css colors. They can be either:\n",
    "   - html colors (link) `'white'`\n",
    "   - hex `'#000000'`\n",
    "   - rgb `'rgb(0, 0, 0)'`.\n",
    "\n",
    "```python\n",
    "col_sc = ColorScale(colors=['yellow', 'red'])\n",
    "```\n",
    "- Using one of `bqplot`'s color-schemes. As of now we support all the colorbrewer schemes (link), as well as the matplotlib schemes 'viridis', 'magma', 'inferno' and 'plasma'.\n",
    "```python\n",
    "col_sc = ColorScale(scheme=['viridis'])\n",
    "```\n",
    "\n",
    "The color scale then linearly interpolates between its colors.\n",
    "\n",
    "### ColorAxis\n",
    "\n",
    "A `ColorAxis`, like other `Axis` types, takes a color scale as input. It can then be displayed in a `Figure`.\n",
    "\n",
    "```python\n",
    "ax_col = ColorAxis(scale=col_sc)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "import bqplot.pyplot as plt\n",
    "from bqplot import ColorScale, DateColorScale, OrdinalColorScale, ColorAxis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# setup data for plotting\n",
    "np.random.seed(0)\n",
    "n = 100\n",
    "x_data = range(n)\n",
    "y_data = np.cumsum(np.random.randn(n) * 100.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def create_fig(color_scale, color_data, fig_margin=None):\n",
    "    # allow some margin on right for color bar\n",
    "    if fig_margin is None:\n",
    "        fig_margin = dict(top=50, bottom=70, left=50, right=100)\n",
    "    fig = plt.figure(title='Up and Down', fig_margin=fig_margin)\n",
    "    \n",
    "    # setup color scale\n",
    "    plt.scales(scales={'color': color_scale})\n",
    "    \n",
    "    # show color bar on right\n",
    "    axes_options = {'color': {'orientation': 'vertical', 'side': 'right'}}\n",
    "    scat = plt.scatter(x_data, y_data, color=color_data, stroke='black', axes_options=axes_options)\n",
    "    return fig"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "fig = create_fig(ColorScale(), y_data)\n",
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### Attributes\n",
    "`ColorScales` share attributes with the other `Scale` types:\n",
    "- Their domain can be manually constrained with the `min` and `max` attributes\n",
    "- They can be inversed by setting the `reverse` attribute to `True`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "color_scale = fig.marks[0].scales['color']\n",
    "color_scale.min = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "color_scale.reverse = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "#### Mid\n",
    "In addition they also have a `mid` attribute, a value that will be mapped to the middle color. This is especially suited to diverging color schemes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "color_scale.min = None\n",
    "color_scale.mid = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## DateColorScale\n",
    "\n",
    "The `DateColorScale` is a color scale for dates. It works in every way like the regular `ColorScale`, except that its `min`, `mid` and `max` attributes — if defined — must be date elements (`datetime`, `numpy` or `pandas`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "fig_margin = dict(top=50, bottom=70, left=50, right=200)\n",
    "date_col_sc = DateColorScale()\n",
    "dates = pd.date_range(start='2015-01-01', periods=n)\n",
    "create_fig(date_col_sc, dates, fig_margin=fig_margin)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "date_col_sc.min = pd.datetime(2016, 2, 28)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Color Schemes\n",
    "\n",
    "Use the following widgets to browse through the available color schemes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from bqplot.market_map import MarketMap\n",
    "\n",
    "from ipywidgets import IntSlider, SelectionSlider, Dropdown\n",
    "from ipywidgets import VBox, HBox, Layout\n",
    "from traitlets import link"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### Diverging schemes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "div_schemes = [\n",
    "    'Spectral',\n",
    "    'RdYlGn',\n",
    "    'RdBu',\n",
    "    'PiYG',\n",
    "    'PRGn',\n",
    "    'RdYlBu',\n",
    "    'BrBG',\n",
    "    'RdGy',\n",
    "    'PuOr',\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def scheme_inspector(fig, schemes, title=''):\n",
    "    '''\n",
    "    Takes a Figure and a list of schemes and returns the Figure along with\n",
    "    dropdown to go through the different schemes\n",
    "    '''\n",
    "    \n",
    "    # Get the color scale\n",
    "    col_sc = fig.marks[0].scales['color']\n",
    "    \n",
    "    # Create the widgets to select the colorscheme\n",
    "    scheme_dd = Dropdown(description='Scheme',\n",
    "                         options=schemes)\n",
    "    \n",
    "    def update_scheme(*args):\n",
    "        col_sc.scheme = scheme_dd.value\n",
    "\n",
    "    scheme_dd.observe(update_scheme, 'value')    \n",
    "    update_scheme()\n",
    "    return VBox([scheme_dd, fig])\n",
    "\n",
    "scheme_inspector(create_fig(ColorScale(), y_data), div_schemes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "### Non-diverging schemes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "lin_schemes = [\n",
    "    'OrRd',\n",
    "    'PuBu',\n",
    "    'BuPu',\n",
    "    'Oranges',\n",
    "    'BuGn',\n",
    "    'YlOrBr',\n",
    "    'YlGn',\n",
    "    'Reds',\n",
    "    'RdPu',\n",
    "    'Greens',\n",
    "    'YlGnBu',\n",
    "    'Purples',\n",
    "    'GnBu',\n",
    "    'Greys',\n",
    "    'YlOrRd',\n",
    "    'PuRd',\n",
    "    'Blues',\n",
    "    'PuBuGn',\n",
    "    'viridis',\n",
    "    'plasma',\n",
    "    'inferno',\n",
    "    'magma'\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "scheme_inspector(create_fig(ColorScale(), y_data), lin_schemes, title='Non-diverging schemes')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## OrdinalColorScale\n",
    "\n",
    "The `OrdinalColorScale` is a color scale for categorical data, i.e. data that does not have an intrinsic order.\n",
    "\n",
    "The scale colors may be specified by the user, or chosen from a set scheme. As of now, the supported color schemes are the colorbrewer categorical schemes, listed here along with their maximum number of colors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "ord_schemes = {\n",
    "    'Set2': 8,\n",
    "    'Accent': 8,\n",
    "    'Set1': 9,\n",
    "    'Set3': 12,\n",
    "    'Dark2': 8,\n",
    "    'Paired': 12,\n",
    "    'Pastel2': 8,\n",
    "    'Pastel1': 9,\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def partition(array, n_groups):\n",
    "    n_elements = len(array)\n",
    "    if n_groups > n_elements:\n",
    "        return np.arange(n_elements)\n",
    "    n_per_group = n_elements // n_groups + (n_elements % n_groups > 0)\n",
    "    return np.tile(range(1, n_groups+1), n_per_group)[:n_elements]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true,
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "# Define the control widgets\n",
    "n_groups_slider = IntSlider(description='n colors', min=3)\n",
    "scheme_dd = Dropdown(description='Scheme',\n",
    "                     options=ord_schemes)\n",
    "    \n",
    "def update_scheme(*args):\n",
    "    col_sc.scheme = scheme_dd.label\n",
    "    ax_c.label = scheme_dd.label\n",
    "    n_groups_slider.max = scheme_dd.value\n",
    "\n",
    "def update_categories(*args):\n",
    "    groups = partition(names, n_groups_slider.value)\n",
    "    market_map.color = groups\n",
    "    market_map.groups = groups\n",
    "\n",
    "n_groups_slider.observe(update_categories, 'value')\n",
    "scheme_dd.observe(update_scheme)\n",
    "\n",
    "# Define the bqplot marketmap\n",
    "names = range(100)\n",
    "\n",
    "col_sc = OrdinalColorScale()\n",
    "ax_c = ColorAxis(scale=col_sc)\n",
    "\n",
    "market_map = MarketMap(names=names,\n",
    "                       display_text=['' for _ in names],\n",
    "                       scales={'color': col_sc}, axes=[ax_c],\n",
    "                       layout=Layout(min_width='800px', min_height='600px'))\n",
    "update_scheme()\n",
    "update_categories()\n",
    "\n",
    "VBox([HBox([scheme_dd, n_groups_slider]), market_map])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
